/* SPDX-License-Identifier: GPL-2.0 */
#ifndef OCFS2_ISO_H
#define OCFS2_ISO_H

#define OCFS2_PROC_FS_READONLY_FILES        "ro_files"
#define OCFS2_PROC_FS_RO_ISO_SWITCH			"ro_switch"
#define OCFS2_PROC_FS_RO_ISO_RESET			"ro_reset"
#define OCFS2_PROC_FS_RO_ISO_LIMIT			"ro_limit"

#define OCFS2_DEFAULT_RO_LIMIT 20
#define OCFS2_PROC_TIME_LEN 20
#define OCFS2_ISO_NODE_NOT_MATCHED 2

#ifndef OCFS2_RO_FUNC_MAX_LEN
#define OCFS2_RO_FUNC_MAX_LEN  44
#endif

enum ocfs2_rip_type {
	OCFS2_RO_ISO_INODE_NO_BH = 1,      /* inode，fe_bh is NULL
		* and needs to be manually obtained == extent/xattr case */
	OCFS2_RO_ISO_INODE_WITH_BH,  /* inode，with fe_bh == inline case */
	OCFS2_RO_ISO_FOR_ADL,        /* adl isolation on ocfs2_super == adl case */
	OCFS2_RO_ISO_INODE_BLKNO,        /* general case, for ocfs2_rip_by_blkno */
	OCFS2_RO_ISO_TO_ERROR,        /* degenerate to ocfs2_error */
};

/*
 * ocfs2_isolation params. the types are classified into multiple types.
 *
 * sizeof(struct ocfs2_ro_iso_param) == 24
 * */
struct ocfs2_ro_iso_param {
	enum ocfs2_rip_type ro_type;
	struct inode *inode;
	struct buffer_head *fe_bh;
	u64 blkno;
	int *status;
};

struct ocfs2_ro_iso_param *ocfs2_rip_build(int type, struct inode *inode,
		struct buffer_head *fe_bh, int *status);
struct ocfs2_ro_iso_param *ocfs2_rip_build_t1(struct inode *inode, int *status);
struct ocfs2_ro_iso_param *ocfs2_rip_build_t2(struct inode *inode,
		struct buffer_head *fe_bh, int *status);
struct ocfs2_ro_iso_param *ocfs2_rip_build_t3(struct inode *inode, int *status);
struct ocfs2_ro_iso_param *ocfs2_rip_by_blkno(u64 blkno, int *status);

enum ocfs2_flush_rid_type {
	OCFS2_RO_ISO_SYS_CHECK = 0,
	OCFS2_RO_ISO_REC_APPEND,
	OCFS2_RO_ISO_REC_REMOVE
};

void ocfs2_handle_ro_isolation(struct super_block *sb,
		struct ocfs2_ro_iso_param *rip, const char *func);
int ocfs2_flush_inode_isolation(struct ocfs2_super *osb, struct ocfs2_ro_iso_param *rip);
int ocfs2_flush_sys_isolation_block(struct ocfs2_super *osb, u64 blkno, const char *func,
		struct timespec64 *time, enum ocfs2_flush_rid_type type);

int ocfs2_read_rolimit_from_disk(struct ocfs2_super *osb, unsigned int *limit);
int ocfs2_write_rolimit_to_disk(struct ocfs2_super *osb, unsigned int limit);
int ocfs2_check_inode_ro_flag(struct ocfs2_super *osb, struct buffer_head *di_bh);
int ocfs2_inode_lock_and_check_ro_flag(struct inode *inode);
int ocfs2_check_inode_ro_on_super(struct ocfs2_super *osb, u64 blkno);

struct ocfs2_ro_isolation_item {
	struct list_head ro_list;  // 16
	struct timespec64 ro_time;  // 16
	u64 ro_blkno; // 8
	struct ocfs2_ro_iso_param *ro_rip; // 8
	char ro_func[OCFS2_RO_FUNC_MAX_LEN]; // 1 * 44（48）
	int ro_node_num; // 4
	bool ro_status; // 1 /* 1 finished, 0 unstarted */
};

void ocfs2_ro_isolation_worker(struct work_struct *work);
void ocfs2_ro_recovery_worker(struct work_struct *work);

__printf(5, 6)
extern void ocfs2_iso(struct super_block *sb, struct ocfs2_ro_iso_param *rip,
		const char *func, int line, const char *fmt, ...);
/*
 * define as __ocfs2_error
 * new code cannot assign func name [__ocfs2_isolation].
 * G.DCL.01 Do not declare or define reserved identifiers.
 *
 * In some scenarios, the ocfs2_iso is degraded to __ocfs2_error.
 *  1. osb_ro_iso_support is off
 *  2. the count of iso files exceeds the limit
 *  3. System inode error and run into ocfs2_iso
 * Related functions are used in super.h. The extern declaration is used here.
 * The implementation of ocfs2_iso is also placed in super.c.
 *
 * */

#define ocfs2_isolation(sb, rip, fmt, args...) \
	ocfs2_iso(sb, rip, __PRETTY_FUNCTION__, __LINE__, fmt, ##args)

int fmt_ctime(struct timespec64 te, char *st);
int ocfs2_ro_files_output(char *buf, struct osb_ro_isolation *ori);
int ocfs2_reset_ro_isolation(struct ocfs2_super *osb, u64 blkno);

#endif /* OCFS2_ISO_H */
